import logging
import traceback
from PyQt5.QtWidgets import QTableWidgetItem, QLabel
from PyQt5.QtCore import Qt
from logger import logger
from plot_widget import PlotWidget
from compare_widget import CompareWidget
from utils import format_hex_with_space

def create_frame_stats_plot(stats: dict, frames: list) -> PlotWidget:
    """创建帧统计显示界面"""
    try:
        plot_widget = PlotWidget()

        # 确保frames是有效的可迭代对象
        if frames is None or len(frames) == 0:
            # 如果没有帧数据，返回空的显示
            plot_widget.total_frames_label.setText(f"总帧数：0")
            return plot_widget

        # 更新总体统计信息
        total_frames = stats['total_frames']
        plot_widget.total_frames_label.setText(f"总帧数：{total_frames}")

        # 设置帧数据到控件
        plot_widget.set_frames(frames)

        # 更新虚拟信道表格
        vc_data = stats['virtual_channels']
        vc_counters = stats['vc_counters']
        plot_widget.vc_table.setRowCount(len(vc_data))

        for i, (vc, count) in enumerate(vc_data.items()):
            # 虚拟信道ID
            vc_item = QTableWidgetItem(f"VC{vc}")
            if vc == 0x3F:
                vc_item.setBackground(Qt.lightGray)  # 空闲帧特殊标记
            plot_widget.vc_table.setItem(i, 0, vc_item)

            # 帧数量
            plot_widget.vc_table.setItem(i, 1, QTableWidgetItem(str(count)))

            # 占比
            ratio = (count / total_frames * 100) if total_frames > 0 else 0
            plot_widget.vc_table.setItem(i, 2, QTableWidgetItem(f"{ratio:.2f}%"))

        # 更新译码状态表格
        decode_data = stats['decode_status']

        # 创建一个新的字典来存储合并后的译码状态统计
        merged_decode_stats = {}

        # 计算译码成功和失败的帧数（用于详细统计信息）
        rs_success_frames = 0
        rs_failed_frames = 0
        ldpc_success_frames = 0
        ldpc_failed_frames = 0
        rs_total_frames = 0
        ldpc_total_frames = 0

        # 添加用于存储失败帧计数的列表
        rs_failed_frame_counts = []
        ldpc_failed_frame_counts = []

        # 创建帧检验结果的映射
        frame_check_results = {}
        for frame in frames[:100]:  # 仅使用部分帧计算映射表
            frame_check_decode = frame['decode_status']
            frame_check_result = frame.get('帧检验结果', 0)
            frame_check_results[frame_check_decode] = frame_check_result

        for frame_check_decode, count in decode_data.items():
            status_key = ""  # 用于合并相同状态的键
            if frame_check_decode == 0:
                status_key = "无R-S译码"
            else:
                bit0_value = frame_check_decode & 0x01
                bit4_value = (frame_check_decode >> 4) & 0x01

                # 构建状态描述
                status_parts = []

                # 获取对应的frame_check_result
                frame_check_result = frame_check_results.get(frame_check_decode, 0)

                # 检查RS译码状态
                if bit0_value == 1:
                    rs_total_frames += count
                    rs_error_bit = (frame_check_result >> 24) & 0x01
                    if rs_error_bit == 0:
                        status_parts.append("RS译码正确")
                        rs_success_frames += count
                    elif rs_error_bit == 1:
                        status_parts.append("RS译码错误")
                        rs_failed_frames += count
                        # 记录失败帧的帧计数
                        for frame in frames[:500]:  # 限制样本数量
                            frame_check_decode_curr = frame['decode_status']
                            frame_check_result_curr = frame.get('帧检验结果', 0)
                            if (frame_check_decode_curr == frame_check_decode and
                                    (frame_check_result_curr >> 24) & 0x01 == 1):
                                rs_failed_frame_counts.append(frame['frame_count'])
                    else:
                        status_parts.append("RS译码无效")
                        rs_failed_frames += count
                        # 记录无效帧的帧计数
                        for frame in frames[:500]:  # 限制样本数量
                            frame_check_decode_curr = frame['decode_status']
                            frame_check_result_curr = frame.get('帧检验结果', 0)
                            if frame_check_decode_curr == frame_check_decode:
                                rs_failed_frame_counts.append(frame['frame_count'])

                # 检查LDPC译码状态
                if bit4_value == 1:
                    ldpc_total_frames += count
                    ldpc_status_byte = (frame_check_result >> 24) & 0xFF
                    # 严格区分LDPC的三种状态：正确(0x00)、失败(0x01)和未知(其他值)
                    if ldpc_status_byte == 0x00:
                        status_parts.append("LDPC译码正确")
                        ldpc_success_frames += count
                    elif ldpc_status_byte == 0x01:
                        status_parts.append("LDPC译码失败")
                        ldpc_failed_frames += count
                        # 记录失败帧的帧计数
                        for frame in frames[:500]:  # 限制样本数量
                            frame_check_decode_curr = frame['decode_status']
                            frame_check_result_curr = frame.get('帧检验结果', 0)
                            if (frame_check_decode_curr == frame_check_decode and
                                    (frame_check_result_curr >> 24) & 0xFF == 0x01):
                                ldpc_failed_frame_counts.append(frame['frame_count'])
                    elif ldpc_status_byte == 0x02:
                        status_parts.append("帧校验开且帧校验错误")
                    else:
                        # 直接在状态文本中显示具体状态值，不写入日志
                        ldpc_info = f"LDPC译码无效(0x{ldpc_status_byte:02X})"
                        status_parts.append(ldpc_info)
                        # 无效状态也计入失败帧数
                        ldpc_failed_frames += count
                        # 记录无效帧的帧计数
                        for frame in frames[:500]:  # 限制样本数量
                            frame_check_decode_curr = frame['decode_status']
                            frame_check_result_curr = frame.get('帧检验结果', 0)
                            if frame_check_decode_curr == frame_check_decode:
                                ldpc_failed_frame_counts.append(frame['frame_count'])

                if status_parts:
                    # 按照固定顺序组合状态字符串，确保相同状态组合会得到相同的键
                    rs_status = next((s for s in status_parts if s.startswith("RS")), "")
                    ldpc_status = next((s for s in status_parts if s.startswith("LDPC")), "")
                    if rs_status and ldpc_status:
                        status_key = f"{rs_status}, {ldpc_status}"
                    else:
                        status_key = rs_status or ldpc_status
                else:
                    # 直接在状态文本中显示具体状态值，不写入日志
                    status_key = f"未知译码状态(0x{frame_check_decode:08X}, Bit0={bit0_value}, Bit4={bit4_value})"

            # 合并相同状态的计数
            if status_key in merged_decode_stats:
                merged_decode_stats[status_key] += count
            else:
                merged_decode_stats[status_key] = count

        # 更新表格显示
        plot_widget.status_table.setRowCount(len(merged_decode_stats))

        for i, (status, count) in enumerate(merged_decode_stats.items()):
            # 译码状态
            plot_widget.status_table.setItem(i, 0, QTableWidgetItem(status))

            # 数量
            plot_widget.status_table.setItem(i, 1, QTableWidgetItem(str(count)))

            # 占比
            ratio = (count / total_frames * 100) if total_frames > 0 else 0
            plot_widget.status_table.setItem(i, 2, QTableWidgetItem(f"{ratio:.2f}%"))

        # 更新详细统计信息
        detailed_stats = stats['detailed_stats']
        
        # 获取帧连续性详细信息
        continuous_info = detailed_stats['frame_count_stats'].get('continuous_info', {
            'continuous_ratio': detailed_stats['frame_count_stats'].get('continuous_ratio', 0.0),
            'discontinuous_frames': [],
            'total_gaps': 0
        })
        
        # 设置帧计数连续性信息到表格
        plot_widget.set_continuity_info(continuous_info)
        
        stats_text = (
            f"帧计数统计：最小 {detailed_stats['frame_count_stats']['min']}，最大 {detailed_stats['frame_count_stats']['max']};\n"
            f"虚拟信道统计：活动信道数 {detailed_stats['virtual_channel_stats']['active_channels']} (不包含空闲信道)\n"
            f"译码状态统计：\n"
            f"  RS译码：总计 {rs_total_frames} 帧，成功 {rs_success_frames} 帧，失败 {rs_failed_frames} 帧\n"
            f"    失败帧：{sorted(rs_failed_frame_counts[:20]) if rs_failed_frame_counts else '无'}{' ...(更多)' if len(rs_failed_frame_counts) > 20 else ''}\n"
            f"  LDPC译码：总计 {ldpc_total_frames} 帧，成功 {ldpc_success_frames} 帧，失败 {ldpc_failed_frames} 帧\n"
            f"    失败帧：{sorted(ldpc_failed_frame_counts[:20]) if ldpc_failed_frame_counts else '无'}{' ...(更多)' if len(ldpc_failed_frame_counts) > 20 else ''}"
        )
        plot_widget.stats_text.setText(stats_text)

        # 显示详细统计信息区域
        plot_widget.stats_label.show()
        plot_widget.stats_text.show()

        # 更新表格列标题说明
        plot_widget.vc_table.setHorizontalHeaderLabels([
            '虚拟信道',
            '帧数量',
            '占比'
        ])

        # 自动调整表格列宽
        plot_widget.vc_table.resizeColumnsToContents()
        plot_widget.status_table.resizeColumnsToContents()

        return plot_widget

    except Exception as e:
        logging.getLogger('frame_analyzer').error(f"创建统计显示界面时发生错误: {str(e)}")
        traceback.print_exc()
        raise

def create_compare_plot(comparison_result, title="文件比对结果"):
    """创建文件比对结果显示"""
    try:
        # 创建CompareWidget
        compare_widget = CompareWidget()

        # 设置比对结果摘要
        total_frames1, total_frames2 = comparison_result['total_frames']
        matching_frames = comparison_result['matching_frames']
        frame_results = comparison_result['frame_results']  # 使用frame_results而不是mismatches

        # 计算匹配率
        match_ratio = (matching_frames / len(frame_results)) * 100 if frame_results else 0

        summary = (
            f"文件1总帧数：{total_frames1}\n"
            f"文件2总帧数：{total_frames2}\n"
            f"匹配帧数：{matching_frames} ({match_ratio:.2f}%)\n"
        )
        compare_widget.summary_label.setText(summary)

        # 填充差异表格
        compare_widget.diff_table.clearContents()
        compare_widget.diff_table.setRowCount(len(frame_results))  # 使用实际的帧结果数量
        compare_widget.diff_table.setColumnCount(3)  # 设置为3列（帧计数、比对结果、差异详情）
        compare_widget.diff_table.setHorizontalHeaderLabels(['虚拟信道帧计数', '比对结果', '差异详情'])

        # 获取帧数据映射
        frames1_dict = {int(frame['frame_count']): frame for frame in comparison_result.get('frames1', [])}
        frames2_dict = {int(frame['frame_count']): frame for frame in comparison_result.get('frames2', [])}

        # 遍历所有帧结果
        for i, frame_result in enumerate(frame_results):
            frame_count = frame_result['frame_count']

            # 尝试从原始帧中获取虚拟信道帧计数
            vc_frame_count = frame_count  # 默认使用帧头的帧计数
            
            if 'frames1' in comparison_result:
                frame_data = next((f for f in comparison_result['frames1'] if f['frame_count'] == frame_count), None)
                # 如果帧的payload长度足够，尝试从payload中获取虚拟信道帧计数
                if frame_data:
                    try:
                        # 使用通用的虚拟信道帧计数提取方法
                        from frame_processor import FrameProcessor
                        vc_frame_count = FrameProcessor.extract_virtual_channel_frame_count(frame_data)
                        if vc_frame_count == 0:
                            vc_frame_count = frame_count  # 如果提取失败，回退到普通帧计数
                    except Exception as e:
                        logger.warning(f"获取虚拟信道帧计数失败: {str(e)}")
            
            if 'frames2' in comparison_result and vc_frame_count == frame_count:
                frame_data = next((f for f in comparison_result['frames2'] if f['frame_count'] == frame_count), None)
                # 如果帧的payload长度足够，尝试从payload中获取虚拟信道帧计数
                if frame_data:
                    try:
                        # 使用通用的虚拟信道帧计数提取方法
                        from frame_processor import FrameProcessor
                        vc_frame_count = FrameProcessor.extract_virtual_channel_frame_count(frame_data)
                        if vc_frame_count == 0:
                            vc_frame_count = frame_count  # 如果提取失败，回退到普通帧计数
                    except Exception as e:
                        logger.warning(f"获取虚拟信道帧计数失败: {str(e)}")

            # 创建帧计数项 - 使用十六进制显示，每两位用空格分隔
            hex_str = format(vc_frame_count, '06X')  # 3字节虚拟信道帧计数格式为6位十六进制
            formatted_hex = ' '.join(hex_str[i:i+2] for i in range(0, len(hex_str), 2))
            count_item = QTableWidgetItem(formatted_hex)
            compare_widget.diff_table.setItem(i, 0, count_item)

            if frame_result['type'] == 'missing_frame':
                result_item = QTableWidgetItem("帧缺失")
                result_item.setBackground(Qt.red)
                result_item.setForeground(Qt.white)
                compare_widget.diff_table.setItem(i, 1, result_item)
                
                # 添加详情
                missing_in = frame_result.get('missing_in', '')
                detail_item = QTableWidgetItem(f"在文件{missing_in}中缺失")
                compare_widget.diff_table.setItem(i, 2, detail_item)
                
            elif frame_result['type'] == 'content_mismatch':
                result_item = QTableWidgetItem("内容不匹配")
                result_item.setBackground(Qt.red)
                result_item.setForeground(Qt.white)
                compare_widget.diff_table.setItem(i, 1, result_item)
                
                # 添加详细差异信息 - 只显示payload差异
                diff_details = []
                
                # 查找并只显示payload的差异
                payload_diff = None
                for diff in frame_result.get('differences', []):
                    if diff['field'] == 'payload':
                        payload_diff = diff
                        break
                
                if payload_diff:
                    # 增强显示详情，显示具体字节差异
                    byte_diffs = []
                    for byte_diff in payload_diff.get('differences', []):
                        if 'type' in byte_diff and byte_diff['type'] == 'length_mismatch':
                            byte_diffs.append(f"负载长度不匹配 (文件1={byte_diff['length1']} 文件2={byte_diff['length2']})")
                        elif 'type' in byte_diff and byte_diff['type'] == 'too_many_diffs':
                            byte_diffs.append(f"差异过多(超过{byte_diff['limit']}处)")
                        elif 'byte_position' in byte_diff:
                            # 显示具体字节位置和值差异
                            pos = byte_diff['byte_position']
                            val1 = byte_diff.get('value1', byte_diff.get('byte1', 0))
                            val2 = byte_diff.get('value2', byte_diff.get('byte2', 0))
                            diff_bits = byte_diff.get('diff_bits', '')
                            
                            # 如果有位差异信息，显示具体哪些位不同
                            if diff_bits:
                                # 找出哪些位不同（1表示不同）
                                diff_positions = [7-i for i, bit in enumerate(diff_bits) if bit == '1']
                                bits_info = f"位{','.join(map(str, diff_positions))}不同" if diff_positions else ""
                                byte_diffs.append(f"字节位置0x{pos:04X}: 文件1=0x{val1:02X}, 文件2=0x{val2:02X} ({bits_info})")
                            else:
                                byte_diffs.append(f"字节位置0x{pos:04X}: 文件1=0x{val1:02X}, 文件2=0x{val2:02X}")
                
                    # 显示所有差异，不限制数量
                    total_diff_count = len(byte_diffs)
                    diff_summary = f"数据区: 共{total_diff_count}处差异: " + "; ".join(byte_diffs)
                    
                    diff_details.append(diff_summary)
                else:
                    # 如果没有找到payload差异但类型是content_mismatch，可能是虚拟信道或译码状态不同
                    diff_details.append("数据区无差异")
                
                detail_item = QTableWidgetItem("; ".join(diff_details))
                compare_widget.diff_table.setItem(i, 2, detail_item)
                
            else:  # matching
                result_item = QTableWidgetItem("完全匹配")
                result_item.setBackground(Qt.green)
                result_item.setForeground(Qt.black)
                compare_widget.diff_table.setItem(i, 1, result_item)
                
                # 对于匹配的帧，差异详情为空
                compare_widget.diff_table.setItem(i, 2, QTableWidgetItem("帧内容完全一致"))

        # 调整表格列宽
        compare_widget.diff_table.resizeColumnsToContents()

        # 保存当前比对结果
        compare_widget.current_comparison = comparison_result

        # 添加提示标签，说明双击可查看详情
        hint_label = QLabel("提示: 双击表格行可查看完整差异详情")
        hint_label.setStyleSheet("font-size: 9pt; color: gray;")
        compare_widget.layout.addWidget(hint_label)

        logger.info("成功创建比对结果显示")
        return compare_widget

    except Exception as e:
        logger.error(f"创建比对结果显示失败: {str(e)}", exc_info=True)
        raise